package org.jeecg.modules.pipe.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.constant.DeviceConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.SelectTreeModel;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.pipe.entity.*;
import org.jeecg.modules.pipe.mapper.*;
import org.jeecg.modules.pipe.service.ISectionService;
import org.jeecg.modules.pipe.vo.PipeMarkerVo;
import org.jeecg.modules.pipe.vo.PipeQueryVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @Description: 管网管段
 * @Author: jeecg-boot
 * @Date:   2024-05-14
 * @Version: V1.0
 */
@Service
public class SectionServiceImpl extends ServiceImpl<SectionMapper, Section> implements ISectionService {

    @Autowired
    private WaterPlantMapper waterPlantMapper;
    @Autowired
    private PumpStationMapper pumpStationMapper;
    @Autowired
    private SectionMapper sectionMapper;
    @Autowired
    private MonitorPointMapper monitorPointMapper;
    @Autowired
    private PipeFlowLeakageMapper flowLeakageMapper;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public void addSection(Section section) {
        //新增时设置hasChild为0
        section.setHasChild(ISectionService.NOCHILD);
        if(oConvertUtils.isEmpty(section.getPid())){
            section.setPid(ISectionService.ROOT_PID_VALUE);
        }else{
            //如果当前节点父ID不为空 则设置父节点的hasChildren 为1
            Section parent = baseMapper.selectById(section.getPid());
            if(parent!=null && !"1".equals(parent.getHasChild())){
                parent.setHasChild("1");
                baseMapper.updateById(parent);
            }
        }
        baseMapper.insert(section);
    }

    @Override
    public void updateSection(Section section) {
        Section entity = this.getById(section.getId());
        if(entity==null) {
            throw new JeecgBootException("未找到对应实体");
        }
        String old_pid = entity.getPid();
        String new_pid = section.getPid();
        if(!old_pid.equals(new_pid)) {
            updateOldParentNode(old_pid);
            if(oConvertUtils.isEmpty(new_pid)){
                section.setPid(ISectionService.ROOT_PID_VALUE);
            }
            if(!ISectionService.ROOT_PID_VALUE.equals(section.getPid())) {
                baseMapper.updateTreeNodeStatus(section.getPid(), ISectionService.HASCHILD);
            }
        }
        baseMapper.updateById(section);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteSection(String id) throws JeecgBootException {
        //查询选中节点下所有子节点一并删除
        id = this.queryTreeChildIds(id);
        if(id.indexOf(",")>0) {
            StringBuffer sb = new StringBuffer();
            String[] idArr = id.split(",");
            for (String idVal : idArr) {
                if(idVal != null){
                    Section section = this.getById(idVal);
                    String pidVal = section.getPid();
                    //查询此节点上一级是否还有其他子节点
                    List<Section> dataList = baseMapper.selectList(new QueryWrapper<Section>().eq("pid", pidVal).notIn("id",Arrays.asList(idArr)));
                    boolean flag = (dataList == null || dataList.size() == 0) && !Arrays.asList(idArr).contains(pidVal) && !sb.toString().contains(pidVal);
                    if(flag){
                        //如果当前节点原本有子节点 现在木有了，更新状态
                        sb.append(pidVal).append(",");
                    }
                }
            }
            //批量删除节点
            baseMapper.deleteBatchIds(Arrays.asList(idArr));
            //修改已无子节点的标识
            String[] pidArr = sb.toString().split(",");
            for(String pid : pidArr){
                this.updateOldParentNode(pid);
            }
        }else{
            Section section = this.getById(id);
            if(section==null) {
                throw new JeecgBootException("未找到对应实体");
            }
            updateOldParentNode(section.getPid());
            baseMapper.deleteById(id);
        }
    }

    @Override
    public List<Section> queryTreeListNoPage(QueryWrapper<Section> queryWrapper) {
        List<Section> dataList = baseMapper.selectList(queryWrapper);
        List<Section> mapList = new ArrayList<>();
        for(Section data : dataList){
            String pidVal = data.getPid();
            //递归查询子节点的根节点
            if(pidVal != null && !ISectionService.NOCHILD.equals(pidVal)){
                Section rootVal = this.getTreeRoot(pidVal);
                if(rootVal != null && !mapList.contains(rootVal)){
                    mapList.add(rootVal);
                }
            }else{
                if(!mapList.contains(data)){
                    mapList.add(data);
                }
            }
        }
        return mapList;
    }

    @Override
    public List<SelectTreeModel> queryListByCode(String parentCode) {
        String pid = ROOT_PID_VALUE;
        if (oConvertUtils.isNotEmpty(parentCode)) {
            LambdaQueryWrapper<Section> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Section::getPid, parentCode);
            List<Section> list = baseMapper.selectList(queryWrapper);
            if (list == null || list.size() == 0) {
                throw new JeecgBootException("该编码【" + parentCode + "】不存在，请核实!");
            }
            if (list.size() > 1) {
                throw new JeecgBootException("该编码【" + parentCode + "】存在多个，请核实!");
            }
            pid = list.get(0).getId();
        }
        return baseMapper.queryListByPid(pid, null);
    }

    @Override
    public List<SelectTreeModel> queryListByPid(String pid) {
        if (oConvertUtils.isEmpty(pid)) {
            pid = ROOT_PID_VALUE;
        }
        return baseMapper.queryListByPid(pid, null);
    }

    /**
     * 根据所传pid查询旧的父级节点的子节点并修改相应状态值
     * @param pid
     */
    private void updateOldParentNode(String pid) {
        if(!ISectionService.ROOT_PID_VALUE.equals(pid)) {
            Long count = baseMapper.selectCount(new QueryWrapper<Section>().eq("pid", pid));
            if(count==null || count<=1) {
                baseMapper.updateTreeNodeStatus(pid, ISectionService.NOCHILD);
            }
        }
    }

    /**
     * 递归查询节点的根节点
     * @param pidVal
     * @return
     */
    private Section getTreeRoot(String pidVal){
        Section data =  baseMapper.selectById(pidVal);
        if(data != null && !ISectionService.ROOT_PID_VALUE.equals(data.getPid())){
            return this.getTreeRoot(data.getPid());
        }else{
            return data;
        }
    }

    /**
     * 查询节点
     * @param id
     * @return
     */
    @Override
    public PipeMarkerVo getPipeMarkNode(String id){
        // 当前租户
        String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");
        Object markObj = redisUtil.hget(DeviceConstant.DEVICE_PIPE_SECTION_DATA + "::" + tenantId, id);
        if(null != markObj){
            return  (PipeMarkerVo)markObj;
        }
        Section data =  baseMapper.selectById(id);
        PipeMarkerVo markerVo = setCache(data);
        return markerVo;

    }

    /**
     * 根据id查询所有子节点id
     * @param ids
     * @return
     */
    private String queryTreeChildIds(String ids) {
        //获取id数组
        String[] idArr = ids.split(",");
        StringBuffer sb = new StringBuffer();
        for (String pidVal : idArr) {
            if(pidVal != null){
                if(!sb.toString().contains(pidVal)){
                    if(sb.toString().length() > 0){
                        sb.append(",");
                    }
                    sb.append(pidVal);
                    this.getTreeChildIds(pidVal,sb);
                }
            }
        }
        return sb.toString();
    }

    /**
     * 递归查询所有子节点
     * @param pidVal
     * @param sb
     * @return
     */
    private StringBuffer getTreeChildIds(String pidVal,StringBuffer sb){
        List<Section> dataList = baseMapper.selectList(new QueryWrapper<Section>().eq("pid", pidVal));
        if(dataList != null && dataList.size()>0){
            for(Section tree : dataList) {
                if(!sb.toString().contains(tree.getId())){
                    sb.append(",").append(tree.getId());
                }
                this.getTreeChildIds(tree.getId(),sb);
            }
        }
        return sb;
    }


    @Override
    public void saveSection(Section section) {
        if(StringUtils.isNotEmpty(section.getPid())){
            if(StringUtils.isEmpty(section.getBeginLat())){
                Section parentSection = sectionMapper.selectById(section.getPid());
                section.setBeginLong(parentSection.getEndLong());
                section.setBeginLat(parentSection.getEndLat());
            }
        }

        if(StringUtils.isNotEmpty(section.getPumpId())){
            if(StringUtils.isEmpty(section.getBeginLat())){
                PumpStation pumpStation = pumpStationMapper.selectById(section.getPumpId());
                section.setBeginLong(pumpStation.getLongitude());
                section.setBeginLat(pumpStation.getLatitude());
            }
        }else if(StringUtils.isNotEmpty(section.getPlantId() )){
            if(StringUtils.isEmpty(section.getBeginLat())){
                WaterPlant waterPlant = waterPlantMapper.selectById(section.getPlantId());
                section.setBeginLong(waterPlant.getLongitude());
                section.setBeginLat(waterPlant.getLatitude());
            }
        }

        if(StringUtils.isNotEmpty(section.getId())){
            this.updateById(section);
        }else{
            this.save(section);
        }
    }

    /**
     * 获取管段Marker
     * @param queryVo
     * @return
     */
    @Override
    public List<PipeMarkerVo> getSectionMarker(PipeQueryVo queryVo) {
        return sectionMapper.getSectionMarker(queryVo);
    }

    /**
     * 获取管网Marker
     *  -水厂
     *  -泵站
     *  -管段
     *  -监测点
     *
     * 这个需要缓存起来
     * 一旦上级阀门关闭，下级管段改变管段颜色，直接改变缓存，不用改库
     *
     * @param queryVo
     * @return
     */
    @Override
    public List<PipeMarkerVo> getPipeMarker(PipeQueryVo queryVo) {
        List<PipeMarkerVo> markerLs = new ArrayList();

        // 当前租户
        String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");

        /** 水厂*/
        List<PipeMarkerVo> markerVoList = waterPlantMapper.getWaterPlantMarker(queryVo);
        if(null != markerVoList && markerVoList.size() > 0){
            markerLs.addAll(markerVoList);
        }

        /** 泵站*/
        markerVoList = pumpStationMapper.getPumpStationMarker(queryVo);
        if(null != markerVoList && markerVoList.size() > 0){
            markerLs.addAll(markerVoList);
        }

        /**管段*/
        // 管段缓存
        Set<Object> sectionObjSet = redisUtil.sGet(DeviceConstant.DEVICE_PIPE_SECTION_SET + "::" + tenantId);
        if(null != sectionObjSet && sectionObjSet.size() > 0){
            for (Object sectionKeyObj : sectionObjSet) {
                PipeMarkerVo sectionMarkerVo = getPipeMarkNode(sectionKeyObj.toString());
                markerLs.add(sectionMarkerVo);
            }
        }else{
            markerVoList = sectionMapper.getSectionMarker(queryVo);
            if(null != markerVoList && markerVoList.size() > 0){
                markerLs.addAll(markerVoList);

                // 需要缓存起来
                for (PipeMarkerVo markerVo : markerVoList) {
                    redisUtil.setRemove(DeviceConstant.DEVICE_PIPE_SECTION_SET+"::"+tenantId,markerVo.getId()+"");
                    redisUtil.sSet(DeviceConstant.DEVICE_PIPE_SECTION_SET+"::"+tenantId,markerVo.getId()+"");
                    redisUtil.hset(DeviceConstant.DEVICE_PIPE_SECTION_DATA+"::"+tenantId,markerVo.getId()+"",markerVo);
                }
            }
        }

        /** 监测点*/
        markerVoList = monitorPointMapper.getMonitorPointMarker(queryVo);
        if(null != markerVoList && markerVoList.size() > 0){
            markerLs.addAll(markerVoList);
        }
        return markerLs;
    }

    /**
     * 管网关阀-下流影响演示
     * @param queryVo
     * @return
     */
    @Override
    public String pipeCloseFlow(PipeQueryVo queryVo) {
        /**1.根据监测点-所在首段管段*/
        MonitorPoint point = monitorPointMapper.selectById(queryVo.getId());
        String pipeIds = point.getPipeId();
        if(StringUtils.isEmpty(pipeIds)){
            throw new JeecgBootException("未配置监测点的首段下流管段");
        }
        // 当前租户
        String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");
        List<PipeMarkerVo> markerLs = new ArrayList();

        /**2.遍历管段，下级管段*/
        String[] pipeArrs = pipeIds.split(",");
        for (String pipeArr : pipeArrs) {
            // 管段缓存
            PipeMarkerVo sectionMarkerVo = getPipeMarkNode(pipeArr);
            markerLs.add(sectionMarkerVo);
            markerLs.addAll(getChildPipeByParentId(pipeArr,tenantId));
        }
        /**3.改变下级管段颜色*/
        if(markerLs.size()>0){
            for (PipeMarkerVo markerVo : markerLs) {
                if(null != markerVo) {
                    markerVo.setColor("F5A623");
                    redisUtil.hset(DeviceConstant.DEVICE_PIPE_SECTION_DATA + "::" + tenantId, markerVo.getId() + "",
                            markerVo, 300);
                }
            }
        }
        return "成功";
    }

    /**
     * 管网漏损-演示
     * @param queryVo
     * @return
     */
    @Override
    public List<PipeMarkerVo> pipeFlowLeakage(PipeQueryVo queryVo) {
        /**
         * 1.查询当前监测点最近（当天）漏损数据
         * 2.仅展示，当前监测点所在管段-下一级流量设备的所经管段
         *
         */
        List<PipeMarkerVo> markerLs = new ArrayList();
        // 当前租户
        String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");

        /**1.根据监测点的流量设备-所在首段管段*/
        String today = DateUtils.getDate("yyyy-MM-dd");
        List<PipeFlowLeakage> leakageList = flowLeakageMapper.selectList(Wrappers.<PipeFlowLeakage>lambdaQuery()
                .eq(PipeFlowLeakage::getDeviceId, queryVo.getId())
                .ge(PipeFlowLeakage::getCreateTime, today));

        if(null != leakageList && leakageList.size() > 0){
            // 一个监测点一天 就一条数据
            PipeFlowLeakage flowLeakage = leakageList.get(0);
            String childrenNode = flowLeakage.getChildrenNode(); // 最前面有带逗号

            if(StringUtils.isNotEmpty(childrenNode)){
                childrenNode = flowLeakage.getPipeId()+childrenNode;
            }

            String[] nodeArr = childrenNode.split(",");
            for (String nodeStr : nodeArr) {
                // 管段缓存
                PipeMarkerVo sectionMarkerVo = getPipeMarkNode(nodeStr);
                if(null != sectionMarkerVo){
                    markerLs.add(sectionMarkerVo);
                }
            }

            /**3.改变下级管段颜色*/
            if(markerLs.size()>0){
                for (PipeMarkerVo markerVo : markerLs) {
                    if(null != markerVo) {
                        markerVo.setColor("F5A623"); // #F5A623 黄色
                        redisUtil.hset(DeviceConstant.DEVICE_PIPE_SECTION_DATA + "::" + tenantId, markerVo.getId() + "",
                                markerVo, 100);
                    }
                }
            }
        }
        return markerLs;
    }

    /***
     * 获取缓存管段的下级管段
     * @param pipeArr
     * @param tenantId
     * @return
     */
    private List<PipeMarkerVo> getChildPipeByParentId(String pipeArr, String tenantId) {
        List<PipeMarkerVo> markerLs = new ArrayList();
        // 所有管段缓存ID
        Set<Object> sectionObjSet = redisUtil.sGet(DeviceConstant.DEVICE_PIPE_SECTION_SET + "::" + tenantId);
        if(null != sectionObjSet && sectionObjSet.size() > 0) {
            for (Object sectionKeyObj : sectionObjSet) {
                PipeMarkerVo sectionMarkerVo = getPipeMarkNode(sectionKeyObj.toString());
                if(pipeArr.equals(sectionMarkerVo.getParentId())){
                    markerLs.add(sectionMarkerVo);
                    markerLs.addAll(this.getChildPipeByParentId(sectionMarkerVo.getId(),tenantId));
                }
            }
        }
        return markerLs;
    }
    public PipeMarkerVo setCache(Section section){
        PipeMarkerVo markerVo = new PipeMarkerVo();
        markerVo.setId(section.getId()+"");
        markerVo.setName(section.getName());
        markerVo.setBeginLong(section.getBeginLong());
        markerVo.setBeginLat(section.getBeginLat());
        markerVo.setLongitude(section.getEndLong());
        markerVo.setLatitude(section.getEndLat());
        markerVo.setPaths(section.getPaths());
        markerVo.setType("5");
        markerVo.setColor(section.getPipeColor());
        markerVo.setStatus(section.getStatus()+"");
        markerVo.setParentId(null != section.getPid() ? section.getPid()+"" : null);

        // 当前租户
        String tenantId = oConvertUtils.getString(TenantContext.getTenant(), "0");
        redisUtil.setRemove(DeviceConstant.DEVICE_PIPE_SECTION_SET+"::"+tenantId,section.getId()+"");
        redisUtil.sSet(DeviceConstant.DEVICE_PIPE_SECTION_SET+"::"+tenantId,section.getId()+"");
        redisUtil.hset(DeviceConstant.DEVICE_PIPE_SECTION_DATA+"::"+tenantId,section.getId()+"",markerVo);
        return markerVo;
    }
}
